#pragma once
#include <cstring>
#include <atomic>
#include <vector>
#include <map>
#include <fstream>
#include <cstring>
using namespace std;
#include "m2_air_cdt.h"

struct scene {
	string ruleId;
	int sceneId;
	int local;
	string name;
	string homeId;
	string roomId;
	string type;
	scene() = default;
	scene(const cJSON *scen)
	{
		cJSON *ruleId = cJSON_GetObjectItemCaseSensitive(scen, "ruleId");
		cJSON *sceneId = cJSON_GetObjectItemCaseSensitive(scen, "sceneId");
		cJSON *name = cJSON_GetObjectItemCaseSensitive(scen, "name");
		cJSON *homeId = cJSON_GetObjectItemCaseSensitive(scen, "homeId");
		cJSON *roomId = cJSON_GetObjectItemCaseSensitive(scen, "roomId");
		cJSON *type = cJSON_GetObjectItemCaseSensitive(scen, "type");
		cJSON *local = cJSON_GetObjectItemCaseSensitive(scen, "local");

		this->ruleId = ruleId->valuestring;
		this->sceneId = sceneId->valueint;
		this->name = name->valuestring;
		this->homeId = homeId->valuestring;
		this->roomId = roomId->valuestring;
		this->type = type->valuestring;
		this->local = local->valueint;
	}
};

struct root_device {
	atomic_uint32_t alyid;
	vector<dev_cdt *> devcdt;
	string self_name;

	root_device() : alyid(0)
	{
		ifstream ifile("/etc/aliynun_config/device.json");
		char buf[1024 * 8];
		ifile.read(buf, sizeof(buf));
		cJSON *json = cJSON_Parse(buf);
		if (json == NULL) {
			cout << "cJSON_Parse" << endl;
			exit(0);
		}
		ifile.close();

		ifile.open("/etc/aliynun_config/config.json");
		ifile.read(buf, sizeof(buf));
		cJSON *conf = cJSON_Parse(buf);
		cJSON *self = cJSON_GetObjectItemCaseSensitive(conf, "self");
		cJSON *DevName = cJSON_GetObjectItemCaseSensitive(self, "DevName");
		self_name = DevName->valuestring;
		ifile.close();
		cJSON_Delete(conf);

		cJSON *airs = cJSON_GetObjectItemCaseSensitive(json, "device_list");
		cJSON *air = nullptr;
		cJSON_ArrayForEach(air, airs)
		{
			dev_cdt *cdt = new M2_air_cdt(air, alyid);
			devcdt.push_back(cdt);
		}

		set<int> unused;
		for (int i = 1; i <= 255; i++) {
			unused.insert(i);
		}

		cJSON *scenes = cJSON_GetObjectItemCaseSensitive(json, "Scenario");
		cJSON *scen = NULL;
		cJSON_ArrayForEach(scen, scenes)
		{
			scene *saio = new scene(scen);
			mp_ruleId_sceneId[saio->ruleId] = saio->sceneId;
			int id = saio->sceneId;
			unused.erase(id);

			mp_scene[id] = saio;
			cJSON *conditions = cJSON_GetObjectItemCaseSensitive(scen, "conditions");
			if (cJSON_IsObject(conditions)) {
				char *ptr = cJSON_Print(conditions);
				mp_scene_conditions[id] = ptr;
				free(ptr);
			}

			cJSON *preconditions = cJSON_GetObjectItemCaseSensitive(scen, "preconditions");
			if (cJSON_IsObject(preconditions)) {
				char *ptr = cJSON_Print(preconditions);
				mp_scene_preconditions[id] = ptr;
				free(ptr);
			}

			cJSON *actions = cJSON_GetObjectItemCaseSensitive(scen, "actions");
			cJSON *act = NULL;
			cJSON_ArrayForEach(act, actions)
			{
				cJSON *addr = cJSON_GetObjectItemCaseSensitive(act, "id");
				char *ptr = cJSON_Print(act);
				mp_scene_actions[id].insert({ addr->valuestring, ptr });
				free(ptr);
			}
		}
		cJSON_Delete(json);

		for (auto it = unused.rbegin(); it != unused.rend(); it++) {
			unused_id.push_back(*it);
		}
	}

	friend ostream &operator<<(ostream &os, root_device &root)
	{
		cJSON *json = cJSON_CreateObject();
		cJSON *air_list = cJSON_AddArrayToObject(json, "device_list");
		for (auto it = root.devcdt.begin(); it != root.devcdt.end(); it++) {
			cJSON *air = (*it)->to_json();
			cJSON_AddItemToArray(air_list, air);
		}

		cJSON *scene = cJSON_AddArrayToObject(json, "Scenario");
		for (auto it = root.mp_scene.begin(); it != root.mp_scene.end(); it++) {
			int id = it->first;
			cJSON *saio = cJSON_CreateObject();
			cJSON_AddStringToObject(saio, "type", it->second->type.c_str());
			cJSON_AddStringToObject(saio, "roomId", it->second->roomId.c_str());
			cJSON_AddStringToObject(saio, "name", it->second->name.c_str());
			cJSON_AddStringToObject(saio, "ruleId", it->second->ruleId.c_str());
			cJSON_AddStringToObject(saio, "homeId", it->second->homeId.c_str());
			cJSON_AddNumberToObject(saio, "local", it->second->local);
			cJSON_AddNumberToObject(saio, "sceneId", id);

			cJSON *conditions = cJSON_Parse(root.mp_scene_conditions[id].c_str());
			cJSON_AddItemToObject(saio, "conditions", conditions);

			cJSON *preconditions = cJSON_Parse(root.mp_scene_preconditions[id].c_str());
			cJSON_AddItemToObject(saio, "preconditions", preconditions);

			cJSON *actions = cJSON_AddArrayToObject(saio, "actions");
			for (auto ait = root.mp_scene_actions[id].begin(); ait != root.mp_scene_actions[id].end(); ait++) {
				cJSON *act = cJSON_Parse(ait->second.c_str());
				cJSON_AddItemToArray(actions, act);
			}
			cJSON_AddItemToArray(scene, saio);
		}

		char *ptr = cJSON_Print(json);
		os << ptr << endl;
		free(ptr);
		cJSON_Delete(json);
		return os;
	}

	int get_all_devstatus(char *buf, int len)
	{
		cJSON *json = cJSON_CreateObject();
		cJSON *devs = cJSON_AddArrayToObject(json, "Devstatus");
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->get_all_devstatus(devs);
		}
		cJSON_PrintPreallocated(json, buf, len, 1);
		cJSON_Delete(json);
		return strlen(buf);
	}

	int get_status_byaddr(char *addr, char *buf, int len)
	{
		cJSON *status = NULL;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			if ((*it)->get_status_byaddr(addr, &status) > 0) {
				cJSON_PrintPreallocated(status, buf, len, 1);
				cJSON_Delete(status);
				return 1;
			}
		}
		return 0;
	}

	int get_status_byarea(char *area, char *buf, int len)
	{
		cJSON *json = cJSON_CreateObject();
		cJSON_AddStringToObject(json, "Area", area);
		cJSON *status = cJSON_AddArrayToObject(json, "Devs");
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->get_status_byarea(area, status);
		}
		cJSON_PrintPreallocated(json, buf, len, 1);
		cJSON_Delete(json);
		return strlen(buf);
	}

	int get_status_bysaio(const char *saio, char *buf, int len)
	{
		cJSON *json = cJSON_CreateObject();
		cJSON_AddStringToObject(json, "Scenario", saio);
		cJSON *status = cJSON_AddArrayToObject(json, "Devs");
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->get_status_bysaio(saio, status);
		}
		cJSON_PrintPreallocated(json, buf, len, 1);
		cJSON_Delete(json);
		return strlen(buf);
	}

	int set_property_byaddr(const char *addr, const cJSON *params, int scaned = 0)
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			if ((*it)->set_property_byaddr(addr, params) > 0) {
				return 1;
			}
		}
		return 0;
	}

	int set_property_byarea(const char *area, const cJSON *params)
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->set_property_byarea(area, params);
		}
		return 0;
	}

	int set_property_bysaio(const char *saio, const cJSON *params)
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->set_property_bysaio(saio, params);
		}
		return 0;
	}

	int get_all_dev(char *buf, int len)
	{
		cJSON *json = cJSON_CreateObject();
		cJSON *devs = cJSON_AddArrayToObject(json, "Devs");
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->get_all_dev(devs);
		}
		cJSON_PrintPreallocated(json, buf, len, 1);
		cJSON_Delete(json);
		return strlen(buf);
	}

	int get_dev_byaddr(const char *addr, char *buf, int len)
	{
		cJSON *dev = NULL;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			if ((*it)->get_dev_byaddr(addr, &dev) > 0) {
				cJSON_PrintPreallocated(dev, buf, len, 1);
				cJSON_Delete(dev);
				return 1;
			}
		}
		return 0;
	}

	int get_dev_byarea(const char *area, char *buf, int len)
	{
		cJSON *json = cJSON_CreateObject();
		cJSON_AddStringToObject(json, "Area", area);
		cJSON *devs = cJSON_AddArrayToObject(json, "Devs");
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->get_dev_byarea(area, devs);
		}
		cJSON_PrintPreallocated(json, buf, len, 1);
		cJSON_Delete(json);
		return strlen(buf);
	}

	int get_dev_bysaio(const char *saio, char *buf, int len)
	{
		cJSON *json = cJSON_CreateObject();
		cJSON_AddStringToObject(json, "Scenario", saio);
		cJSON *devs = cJSON_AddArrayToObject(json, "Devs");
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->get_dev_bysaio(saio, devs);
		}
		cJSON_PrintPreallocated(json, buf, len, 1);
		cJSON_Delete(json);
		return strlen(buf);
	}

	int cloud_offline_event()
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->cloud_offline_event();
		}
		return 0;
	}

	int cloud_online_event()
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->cloud_online_event();
		}
		return 0;
	}

	int subdev_login_replay(const cJSON *params)
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->subdev_login_replay(params);
		}
		return 0;
	}

	int topo_get_replay(const cJSON *devs)
	{
		int save = 0;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			save |= (*it)->topo_get_replay(devs);
		}
		return save;
	}

	int sub_register_replay(const cJSON *devs)
	{
		int save = 0;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			save |= (*it)->sub_register_replay(devs);
		}
		return save;
	}

	int topo_add_replay(const cJSON *devs)
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->topo_add_replay(devs);
		}
		return 0;
	}

	int topo_change_notify(const cJSON *params)
	{
		int ret = 0;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			ret |= (*it)->topo_change_notify(params);
		}
		return ret;
	}

	void start()
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			(*it)->start();
		}
	}

	int analysis_scan_online_result(const cJSON *params)
	{
		int ret;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			ret = (*it)->analysis_scan_online_result(params);
			if (ret >= 0) {
				return ret;
			}
		}
		return 0;
	}

	int analysis_scan_offline_result(const cJSON *params)
	{
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			if ((*it)->analysis_scan_offline_result(params) > 0) {
				return 1;
			}
		}
		return 0;
	}

	int set_dev_area(const cJSON *params)
	{
		int ret = 0;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			if ((ret = (*it)->set_dev_area(params)) >= 0) {
				return ret;
			}
		}
		return 0;
	}

	int set_dev_scenario(const cJSON *params)
	{
		int ret = 0;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			if ((ret = (*it)->set_dev_scenario(params)) >= 0) {
				return ret;
			}
		}
		return 0;
	}

	int property_post_replay(const cJSON *params)
	{
		int ret = 0;
		for (auto it = devcdt.begin(); it != devcdt.end(); it++) {
			if ((ret = (*it)->property_post_replay(params)) > 0) {
				return ret;
			}
		}
		return 0;
	}
	/****************************场景处理***************************/
	map<string, int> mp_ruleId_sceneId;
	vector<int> unused_id;
	map<int, scene *> mp_scene;
	map<int, multimap<string, string>> mp_scene_actions;
	map<int, string> mp_scene_conditions;
	map<int, string> mp_scene_preconditions;

	int scence_act_replay(const char *type, const int sceneId, const char *ruleId = NULL, const int code = 0, const char *msg = NULL)
	{
		cJSON *scene_replay = cJSON_CreateObject();
		cJSON_AddStringToObject(scene_replay, "Active", "SCENE_REPLAY");

		cJSON *json = cJSON_AddObjectToObject(scene_replay, "Params");
		cJSON_AddStringToObject(json, "type", type);
		cJSON_AddStringToObject(json, "contentType", "application/json");
		cJSON_AddNumberToObject(json, "contentLengh", 0);
		cJSON *bd = cJSON_AddObjectToObject(json, "body");
		cJSON_AddNumberToObject(bd, "code", code);
		if (msg) {
			cJSON_AddStringToObject(bd, "message", msg);
		} else {
			cJSON_AddStringToObject(bd, "message", "success");
		}
		cJSON *data = cJSON_AddObjectToObject(bd, "data");
		cJSON_AddNumberToObject(data, "sceneId", sceneId);
		if (ruleId) {
			cJSON_AddStringToObject(data, "ruleId", ruleId);
		}

		char *ptr = cJSON_Print(scene_replay);
		send_msg(CLOUD_QUEUE, ptr, strlen(ptr));
		free(ptr);
		cJSON_Delete(scene_replay);
		return 0;
	}

	int aliyun_scenario_set(const cJSON *body)
	{
		if (unused_id.size() == 0) {
			return -1;
		}

		cJSON *ruleId = cJSON_GetObjectItemCaseSensitive(body, "ruleId");
		cJSON *name = cJSON_GetObjectItemCaseSensitive(body, "name");
		cJSON *roomId = cJSON_GetObjectItemCaseSensitive(body, "roomId");
		cJSON *homeId = cJSON_GetObjectItemCaseSensitive(body, "homeId");
		cJSON *type = cJSON_GetObjectItemCaseSensitive(body, "type");
		cJSON *local = cJSON_GetObjectItemCaseSensitive(body, "local");
		if (local == NULL) {
			local = cJSON_CreateNumber(0);
		}
		if (!cJSON_IsString(ruleId) || ruleId->valuestring == NULL || !cJSON_IsString(name) || name->valuestring == NULL || !cJSON_IsString(roomId) ||
		    roomId->valuestring == NULL || !cJSON_IsString(homeId) || homeId->valuestring == NULL || !cJSON_IsString(type) || type->valuestring == NULL) {
			return -1;
		}

		if (mp_ruleId_sceneId[ruleId->valuestring]) {
			int id = mp_ruleId_sceneId[ruleId->valuestring];
			mp_ruleId_sceneId.erase(mp_scene[id]->ruleId);
			delete mp_scene[id];
			mp_scene.erase(id);

			mp_scene_actions[id].clear();
			mp_scene_actions.erase(id);
			mp_scene_conditions.erase(id);
			mp_scene_preconditions.erase(id);
			unused_id.push_back(id);
		}

		int id = unused_id.back();
		unused_id.pop_back();

		mp_ruleId_sceneId[ruleId->valuestring] = id;
		scene *sce = new scene;
		sce->ruleId = ruleId->valuestring;
		sce->sceneId = id;
		sce->name = name->valuestring;
		sce->roomId = roomId->valuestring;
		sce->homeId = homeId->valuestring;
		sce->type = type->valuestring;
		sce->local = local->valueint;
		mp_scene[id] = sce;

		cJSON *conditions = cJSON_GetObjectItemCaseSensitive(body, "conditions");
		if (cJSON_IsObject(conditions)) {
			char *ptr = cJSON_Print(conditions);
			mp_scene_conditions[id] = ptr;
			free(ptr);
		}

		cJSON *preconditions = cJSON_GetObjectItemCaseSensitive(body, "preconditions");
		if (cJSON_IsArray(preconditions)) {
			char *ptr = cJSON_Print(preconditions);
			mp_scene_preconditions[id] = ptr;
			free(ptr);
		}

		cJSON *actions = cJSON_GetObjectItemCaseSensitive(body, "actions");
		cJSON *act = NULL;
		cJSON_ArrayForEach(act, actions)
		{
			cJSON *executorType = cJSON_GetObjectItemCaseSensitive(act, "executorType");
			if (!cJSON_IsString(executorType) || executorType->valuestring == NULL) {
				continue;
			}
			if (executorType->valuestring != string("device")) {
				continue;
			}

			cJSON *addr = cJSON_GetObjectItemCaseSensitive(act, "id");
			char *ptr = cJSON_Print(act);
			mp_scene_actions[id].insert({ addr->valuestring, ptr });
			free(ptr);
		}
		scence_act_replay("issueSceneReply", id, ruleId->valuestring);
		return 0;
	}

	int aliyun_scenario_exec(const cJSON *body)
	{
		cJSON *sceneId = cJSON_GetObjectItemCaseSensitive(body, "sceneId");
		cJSON *ruleId = cJSON_GetObjectItemCaseSensitive(body, "ruleId");
		int id = 0;
		if (cJSON_IsNumber(sceneId)) {
			id = sceneId->valueint;
			if (id == 0) {
				scence_act_replay("execSceneReply", -1, NULL, -1, "scene not exist");
				return -1;
			}
		} else if (cJSON_IsString(ruleId) && ruleId->valuestring != NULL) {
			id = mp_ruleId_sceneId[ruleId->valuestring];
			if (id == 0) {
				scence_act_replay("execSceneReply", id, ruleId->valuestring, -1, "scene not exist");
				return -1;
			}
		}

		for (auto it = mp_scene_actions[id].begin(); it != mp_scene_actions[id].end(); it++) {
			cJSON *act = cJSON_Parse(it->second.c_str());
			cJSON *params = cJSON_GetObjectItemCaseSensitive(act, "params");
			cJSON *properties = cJSON_GetObjectItemCaseSensitive(params, "properties");
			set_property_byaddr(it->first.c_str(), properties);
			cJSON_Delete(act);
		}
		scence_act_replay("execSceneReply", id);
		return 0;
	}

	int aliyun_scenario_update(const cJSON *body)
	{
		cJSON *sceneId = cJSON_GetObjectItemCaseSensitive(body, "sceneId");
		if (!cJSON_IsNumber(sceneId)) {
			return -1;
		}
		int id = sceneId->valueint;
		if (mp_scene.find(id) == mp_scene.end()) {
			return -1;
		}

		cJSON *conditions = cJSON_GetObjectItemCaseSensitive(body, "conditions");
		if (cJSON_IsObject(conditions)) {
			char *ptr = cJSON_Print(conditions);
			mp_scene_conditions[id] = ptr;
			free(ptr);
		}

		cJSON *preconditions = cJSON_GetObjectItemCaseSensitive(body, "preconditions");
		if (cJSON_IsArray(preconditions)) {
			char *ptr = cJSON_Print(preconditions);
			mp_scene_preconditions[id] = ptr;
			free(ptr);
		}

		cJSON *actions = cJSON_GetObjectItemCaseSensitive(body, "actions");
		cJSON *act = NULL;
		cJSON_ArrayForEach(act, actions)
		{
			cJSON *executorType = cJSON_GetObjectItemCaseSensitive(act, "executorType");
			if (!cJSON_IsString(executorType) || executorType->valuestring == NULL) {
				continue;
			}
			if (executorType->valuestring != string("device")) {
				continue;
			}

			cJSON *addr = cJSON_GetObjectItemCaseSensitive(act, "id");
			cJSON *params = cJSON_GetObjectItemCaseSensitive(act, "params");
			cJSON *properties = cJSON_GetObjectItemCaseSensitive(params, "properties");
			mp_scene_actions[id].erase(addr->valuestring);
			char *ptr = cJSON_Print(properties);
			mp_scene_actions[id].insert({ addr->valuestring, ptr });
			free(ptr);
		}
		scence_act_replay("updateSceneReply", id);
		return 0;
	}

	int aliyun_scenario_remove(const cJSON *body)
	{
		cJSON *sceneId = cJSON_GetObjectItemCaseSensitive(body, "sceneId");
		if (!cJSON_IsNumber(sceneId)) {
			return -1;
		}
		int id = sceneId->valueint;

		cJSON *local = cJSON_GetObjectItemCaseSensitive(body, "local");
		if (cJSON_IsNumber(local) && mp_scene[id]->local == 0) {
			scence_act_replay("removeSceneReply", id, mp_scene[id]->ruleId.c_str(), -1, "can not edit cloud scene");
			return -1;
		}

		mp_ruleId_sceneId.erase(mp_scene[id]->ruleId);
		delete mp_scene[id];
		mp_scene.erase(id);

		mp_scene_actions[id].clear();
		mp_scene_actions.erase(id);
		mp_scene_conditions.erase(id);
		mp_scene_preconditions.erase(id);

		unused_id.push_back(id);
		scence_act_replay("removeSceneReply", sceneId->valueint);
		return 1;
	}

	int aliyun_scenario_add_actions(const cJSON *body)
	{
		cJSON *sceneId = cJSON_GetObjectItemCaseSensitive(body, "sceneId");
		cJSON *actions = cJSON_GetObjectItemCaseSensitive(body, "actions");
		if (!cJSON_IsArray(actions) || !cJSON_IsNumber(sceneId)) {
			return -1;
		}

		int id = sceneId->valueint;
		cJSON *local = cJSON_GetObjectItemCaseSensitive(body, "local");
		if (cJSON_IsNumber(local) && mp_scene[id]->local == 0) {
			scence_act_replay("addSceneActionsReply", id, mp_scene[id]->ruleId.c_str(), -1, "can not edit cloud scene");
			return -1;
		}

		cJSON *act = NULL;
		cJSON_ArrayForEach(act, actions)
		{
			cJSON *executorType = cJSON_GetObjectItemCaseSensitive(act, "executorType");
			if (executorType->valuestring != string("device")) {
				return -1;
			}
			cJSON *addr = cJSON_GetObjectItemCaseSensitive(act, "id");
			char *ptr = cJSON_Print(act);
			mp_scene_actions[sceneId->valueint].insert({ addr->valuestring, ptr });
			free(ptr);
		}

		scence_act_replay("addSceneActionsReply", sceneId->valueint);
		return 1;
	}

	int aliyun_scenario_remove_actions(const cJSON *body)
	{
		cJSON *sceneId = cJSON_GetObjectItemCaseSensitive(body, "sceneId");
		cJSON *actionIds = cJSON_GetObjectItemCaseSensitive(body, "actionIds");
		if (!cJSON_IsArray(actionIds) || !cJSON_IsNumber(sceneId)) {
			return -1;
		}

		int id = sceneId->valueint;
		cJSON *local = cJSON_GetObjectItemCaseSensitive(body, "local");
		if (cJSON_IsNumber(local) && mp_scene[id]->local == 0) {
			scence_act_replay("removeSceneActionsReply", id, mp_scene[id]->ruleId.c_str(), -1, "can not edit cloud scene");
			return -1;
		}

		cJSON *act = NULL, *addr = NULL;
		cJSON_ArrayForEach(addr, actionIds)
		{
			mp_scene_actions[sceneId->valueint].erase(addr->valuestring);
		}
		scence_act_replay("removeSceneActionsReply", sceneId->valueint);
		return 1;
	}

	int aliyun_scenario_update_actions(const cJSON *body)
	{
		cJSON *sceneId = cJSON_GetObjectItemCaseSensitive(body, "sceneId");
		cJSON *actions = cJSON_GetObjectItemCaseSensitive(body, "actions");
		if (!cJSON_IsArray(actions) || !cJSON_IsNumber(sceneId)) {
			return -1;
		}

		int id = sceneId->valueint;
		cJSON *local = cJSON_GetObjectItemCaseSensitive(body, "local");
		if (cJSON_IsNumber(local) && mp_scene[id]->local == 0) {
			scence_act_replay("updateSceneActionsReply", id, mp_scene[id]->ruleId.c_str(), -1, "can not edit cloud scene");
			return -1;
		}

		cJSON *act = NULL;
		cJSON_ArrayForEach(act, actions)
		{
			cJSON *addr = cJSON_GetObjectItemCaseSensitive(act, "id");
			mp_scene_actions[sceneId->valueint].erase(addr->valuestring);
			char *ptr = cJSON_Print(act);
			mp_scene_actions[sceneId->valueint].insert({ addr->valuestring, ptr });
			free(ptr);
		}

		scence_act_replay("updateSceneActionsReply", sceneId->valueint);
		return 1;
	}

	int aliyun_scenario_update_baseInfo(const cJSON *body)
	{
		cJSON *sceneId = cJSON_GetObjectItemCaseSensitive(body, "sceneId");
		cJSON *name = cJSON_GetObjectItemCaseSensitive(body, "name");
		if (!cJSON_IsNumber(sceneId) || !cJSON_IsString(name) || name->valuestring == NULL) {
			return -1;
		}

		int id = sceneId->valueint;
		cJSON *local = cJSON_GetObjectItemCaseSensitive(body, "local");
		if (cJSON_IsNumber(local) && mp_scene[id]->local == 0) {
			scence_act_replay("updateSceneActionsReply", id, mp_scene[id]->ruleId.c_str(), -1, "can not edit cloud scene");
			return -1;
		}

		if (mp_scene.find(sceneId->valueint) == mp_scene.end()) {
			return -1;
		}
		mp_scene[sceneId->valueint]->name = name->valuestring;

		scence_act_replay("updateSceneBaseInfoReply", sceneId->valueint);
		return 1;
	}

	int aliyun_scenario_get_all(char *buf, int len)
	{
		cJSON *json = cJSON_CreateObject();
		cJSON *scene = cJSON_AddArrayToObject(json, "Scenario");
		for (auto it = mp_scene.begin(); it != mp_scene.end(); it++) {
			int id = it->first;
			cJSON *saio = cJSON_CreateObject();
			cJSON_AddStringToObject(saio, "type", it->second->type.c_str());
			cJSON_AddStringToObject(saio, "roomId", it->second->roomId.c_str());
			cJSON_AddStringToObject(saio, "name", it->second->name.c_str());
			cJSON_AddStringToObject(saio, "ruleId", it->second->ruleId.c_str());
			cJSON_AddStringToObject(saio, "homeId", it->second->homeId.c_str());
			cJSON_AddNumberToObject(saio, "local", it->second->local);
			cJSON_AddNumberToObject(saio, "sceneId", id);

			cJSON *conditions = cJSON_Parse(mp_scene_conditions[id].c_str());
			cJSON_AddItemToObject(saio, "conditions", conditions);

			cJSON *preconditions = cJSON_Parse(mp_scene_preconditions[id].c_str());
			cJSON_AddItemToObject(saio, "preconditions", preconditions);

			cJSON *actions = cJSON_AddArrayToObject(saio, "actions");
			for (auto ait = mp_scene_actions[id].begin(); ait != mp_scene_actions[id].end(); ait++) {
				cJSON *act = cJSON_Parse(ait->second.c_str());
				cJSON_AddItemToArray(actions, act);
			}
			cJSON_AddItemToArray(scene, saio);
		}

		cJSON_PrintPreallocated(json, buf, len, 1);
		cJSON_Delete(json);
		return 0;
	}
};
